package com.xhy.documents_collection.service.async.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xhy.documents_collection.cache.UserCache;
import com.xhy.documents_collection.entity.PO.task.TaskTimingRecord;
import com.xhy.documents_collection.entity.res.OSSRes;
import com.xhy.documents_collection.enums.EmailEnum;
import com.xhy.documents_collection.enums.TimingEnum;
import com.xhy.documents_collection.exception.OssException;
import com.xhy.documents_collection.holder.UserHolder;
import com.xhy.documents_collection.enums.UploadWayEnum;
import com.xhy.documents_collection.entity.DO.FileDO;
import com.xhy.documents_collection.entity.DO.UploadDO;
import com.xhy.documents_collection.entity.PO.email.EmailSetting;
import com.xhy.documents_collection.entity.PO.task.DownloadRecord;
import com.xhy.documents_collection.entity.PO.task.Task;
import com.xhy.documents_collection.entity.PO.task.TaskRecord;
import com.xhy.documents_collection.entity.PO.team.Team;
import com.xhy.documents_collection.service.*;
import com.xhy.documents_collection.service.async.AsyncService;
import com.xhy.documents_collection.service.task.DownloadRecordService;
import com.xhy.documents_collection.service.task.TaskRecordService;
import com.xhy.documents_collection.service.task.TaskService;
import com.xhy.documents_collection.service.task.TaskTimingRecordService;
import com.xhy.documents_collection.service.team.TeamService;
import com.xhy.documents_collection.utils.OSSUtil;
import com.xhy.documents_collection.utils.SpringUtil;
import org.springframework.context.annotation.Lazy;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * Author: Xhy
 * CreateTime: 2022-12-15 16:14
 */
@Service
public class AsyncServiceImpl implements AsyncService {
    @Resource
    private DownloadRecordService downloadRecordService;

    @Resource
    private TaskRecordService taskRecordService;

    @Resource
    @Lazy
    private EmailSettingService emailSettingService;

    @Resource
    private TaskService taskService;

    @Resource
    private TeamService teamService;

    @Resource
    private FileLogService fileLogService;

    @Resource
    @Lazy
    TaskTimingRecordService taskTimingRecordService;


    // 获取filePath
    private String getFilePath(UploadDO uploadDO){
        TaskRecord taskRecord = uploadDO.getTaskRecord();
        Integer taskId = taskRecord.getTId();
        Task task = taskService.getOne(new QueryWrapper<Task>().eq("id", taskId));
        // 获取团队id
        Integer teamId = task.getTId();
        //获取任务名称
        String taskName = task.getName();
        // 获取团队名称
        String teamName = teamService.getOne(new QueryWrapper<Team>().eq("id", teamId).select("name")).getName();
        // 拼接
        String filePath = teamId+teamName+"/"+taskName+"/"+uploadDO.getFileDO().getFileName();
        return filePath;
    }

    private final static int toM = 1024*1024;

    @Override
    @Async
    public void upload(UploadDO uploadDO) {
        Integer uId = uploadDO.getUId();
        FileDO fileDO = uploadDO.getFileDO();
        TaskRecord taskRecord = uploadDO.getTaskRecord();
        try {
            // 是否已经上传过
            if (!ObjectUtils.isEmpty(taskRecord.getFilePath())){
                // 先删除
                OSSUtil.deleteFile(taskRecord.getFilePath());
            }
            Team team = uploadDO.getTeam();
            String filePath = getFilePath(uploadDO);
            OSSUtil.upload(filePath, fileDO);
            String fileName = fileDO.getFileName();
            // 更新表
            taskRecord.setIsSubmit(true);
            taskRecord.setFilePath(filePath);
            taskRecord.setFileName(fileName);
            taskRecord.setSubmitTime(new Date());
            taskRecord.setFileSize(fileDO.getFileSize());
            taskRecordService.updateById(taskRecord);
            // 修改团队容量
            team.setFileSizeUsed(team.getFileSizeUsed()+fileDO.getFileSize()/toM);
            teamService.updateById(team);
        }catch (OssException e){
            fileLogService.updateState(taskRecord.getId(),uId);
        }

    }


    @Override
    @Async()
    public void deleteFile(TaskRecord taskRecord,Integer uId) {
        UserHolder.set(uId);

        try {
            OSSUtil.deleteFile(taskRecord.getFilePath());
        }catch (OssException e){
            fileLogService.updateState(taskRecord.getId(),uId);
            return;
        }
        taskRecord.setIsSubmit(false);
        taskRecord.setFileName("");
        taskRecord.setFilePath("");
        taskRecord.setFileSize(0l);
        taskRecord.setUrl("");
        taskRecord.setSubmitTime(null);
        taskRecordService.updateById(taskRecord);
    }

    @Override
    @Async
    public void removeByTaskIds(List<Integer> taskIds) {
        List<String> filePaths = taskRecordService
                .list(new QueryWrapper<TaskRecord>()
                        .in("t_id", taskIds)
                        .select("file_path"))
                .stream()
                .map(TaskRecord::getFilePath)
                .filter(filePath->!ObjectUtils.isEmpty(filePath))
                .collect(Collectors.toList());
        OSSUtil.deleteFiles(filePaths);
    }

    @Override
    @Async
    public void downloadFiles(List<TaskRecord> records, Integer userId) {
        List<String> fileNames = records.stream().map(TaskRecord::getFilePath).collect(Collectors.toList());
        long fileSize = records.stream().map(TaskRecord::getFileSize).mapToLong(Long::longValue).sum();
        UserHolder.set(String.valueOf(userId));
        String url = OSSUtil.downloadFilesToZipOss(fileNames);
        DownloadRecord downloadRecord = new DownloadRecord();
        Integer taskId = records.get(0).getTId();
        downloadRecord.setTaskId(taskId);
        downloadRecord.setUserId(userId);
        downloadRecord.setFileSize(fileSize);
        downloadRecord.setUploadWay(UploadWayEnum.MO_UPLOAD.type);
        downloadRecord.setSize(records.size());
        // 拼接filePath和fileName
        downloadRecord.setFileName(taskService.getById(taskId).getName()+".zip");
        downloadRecord.setFilePath(url);
        downloadRecordService.save(downloadRecord);
    }

    /**
     * 上传作业描述,添加or修改
     * @param uploadDO
     */
    @Override
    @Async
    public void uploadTaskDescription(UploadDO uploadDO) {
        // 查询任务
        Integer taskId = uploadDO.getTaskId();
        Task task = taskService.getById(taskId);
        // 删除原本的
        try {
            if (!ObjectUtils.isEmpty(task.getFilePath())){
                OSSUtil.deleteFile(task.getFilePath());
            }
            // 查询团队
            Team team = teamService.getById(task.getTId());
            FileDO fileDO = uploadDO.getFileDO();
            String filePath = team.getId()+team.getName()+"/"+task.getName()+"/"+ System.currentTimeMillis()+fileDO.getFileName();
            fileDO.setPath(filePath);
            OSSUtil.uploadTaskDescription(fileDO);
            task.setFilePath(filePath);
            taskService.updateById(task);
        }catch (OssException e){
            fileLogService.updateState(taskId,uploadDO.getUId());
        }
    }

    @Override
    public void deleteFiles(List<String> filePaths) {
        OSSUtil.deleteFiles(filePaths);
    }

    static final String testMessage = "邮箱测试成功,可以使用。";

    static final String testSubject = "邮箱测试";


    @Override
    @Async
    public void sendTestEmail(EmailSetting emailSetting) {
        String sendUserName = emailSetting.getUserName();
        JavaMailSenderImpl sender = emailSettingService.createMessage(emailSetting);
        MimeMessage message = sender.createMimeMessage();
        //这里的utf-8解决 邮件 内容乱码
        MimeMessageHelper helper = null;
        try {
            helper = new MimeMessageHelper(message, true, "utf-8");
            //当前发送人邮箱（也就是自己）
            helper.setFrom(sendUserName);
            //发送到的邮箱地址
            helper.setTo(sendUserName);
            //邮件主题、标题
            helper.setSubject(testSubject);
            //内容
            helper.setText(testMessage);
            sender.send(message);
            emailSetting.setState(true);
            emailSettingService.updateById(emailSetting);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    @Override
    @Async
    public void addSchedulerTask(TaskTimingRecord taskTimingRecord) {
        Integer way = taskTimingRecord.getWay();
        if (way == EmailEnum.SUBMIT.type){
            submit(taskTimingRecord);
        }else {
            notice(taskTimingRecord);
        }
    }



    private void submit(TaskTimingRecord taskTimingRecord){
        Integer taskId = taskTimingRecord.getTaskId();
        // 获取该任务下的所有非空文件并下载
        List<TaskRecord> taskRecords = taskRecordService.list(new LambdaQueryWrapper<TaskRecord>().eq(TaskRecord::getTId, taskId));
        List<String> filePaths = new ArrayList<>();
        long fileSize = 0;
        for (TaskRecord taskRecord : taskRecords) {
            if (!ObjectUtils.isEmpty(taskRecord.getFilePath())){
                filePaths.add(taskRecord.getFilePath());;
                fileSize+=taskRecord.getFileSize();
            }
        }
        Integer userId = taskTimingRecord.getUserId();
        boolean res = true;
        parseContent(taskTimingRecord);
        if (!ObjectUtils.isEmpty(filePaths)){
            // 下载文件到本地并且获取路径
            OSSRes ossRes = OSSUtil.downloadFilesToZipLocal(filePaths);
            String path = ossRes.getPath();
            if (!ossRes.getState()){
                // 获取出错的path
                String message = ossRes.getMessage();
                String errorMsg = " 有出错的文件,文件为:"+message;
                taskTimingRecord.setContent(taskTimingRecord.getContent()+errorMsg);
            }
            // 发送
            res = emailSettingService.sendTaskFile(taskTimingRecord, path);
            // 修改记录状态
            if (!res){
                taskTimingRecord.setState(TimingEnum.FAILED.type);
                taskTimingRecordService.updateById(taskTimingRecord);
                return;
            }
        }

        // 给自己发送状态邮箱
        EmailSetting emailSetting = emailSettingService.getOne(new LambdaQueryWrapper<EmailSetting>().eq(EmailSetting::getUserId, userId));
        String content = "定时任务:"+taskTimingRecord.getTaskName()+
                "已发送。发送状态:"+(res ? "发送成功。" : "发送失败。") + taskTimingRecord.getContent();
        emailSettingService.send(emailSetting,content);
        taskTimingRecord.setState(TimingEnum.SUCCESS.type);
        taskTimingRecord.setFileSize(fileSize);
        // 添加下载记录
        DownloadRecord downloadRecord = new DownloadRecord();
        downloadRecord.setUserId(userId);
        downloadRecord.setUploadWay(UploadWayEnum.TIMING_UPLOAD.type);
        downloadRecord.setUrl("");
        downloadRecord.setTaskId(taskId);
        downloadRecord.setFileSize(fileSize);
        downloadRecord.setSize(filePaths.size());
        taskTimingRecordService.updateById(taskTimingRecord);
        downloadRecordService.save(downloadRecord);
    }


    private void notice(TaskTimingRecord taskTimingRecord){
        boolean res = true;
        parseContent(taskTimingRecord);
        res = emailSettingService.sendTaskFile(taskTimingRecord, "");
        // 修改记录状态
        if (!res){
            taskTimingRecord.setState(TimingEnum.FAILED.type);
            taskTimingRecordService.updateById(taskTimingRecord);
            return;
        }
        taskTimingRecord.setState(TimingEnum.SUCCESS.type);
        taskTimingRecordService.updateById(taskTimingRecord);

    }


    final static String headCount = "headCount";
    final static String practical = "practical";
    final static String noSubmitNames = "noSubmitNames";

    private void parseContent(TaskTimingRecord taskTimingRecord){
        String content = taskTimingRecord.getContent();
        if (!ObjectUtils.isEmpty(content)){
            List<TaskRecord> taskRecordList = taskRecordService.list(new LambdaQueryWrapper<TaskRecord>().eq(TaskRecord::getTId, taskTimingRecord.getTaskId()));
            if (content.contains(headCount)){
                int count = taskRecordList.size();
                // 获取总人数
                content = content.replace(headCount,String.valueOf(count));
            }
            if (content.contains(practical)){
                // 获取已交的人
                long count = taskRecordList.stream().filter(taskRecord -> taskRecord.getIsSubmit()).count();
                content = content.replace(practical,String.valueOf(count));
            }
            if (content.contains(noSubmitNames)){
                // 获取没交的人名字
                List<Integer> userId = taskRecordList.stream().filter(taskRecord -> !taskRecord.getIsSubmit()).map(TaskRecord::getUId).collect(Collectors.toList());
                List<String> names = UserCache.list(userId);
                // 拼接内容
                String newContent = "";
                StringJoiner joiner = new StringJoiner(",");
                for (String name : names) {
                    joiner.add(name);
                }
                newContent+=joiner.toString()+"。";
                content = content.replace(noSubmitNames,newContent);
            }
            content+="。by:该邮件由文件收集平台定时发送。开发者：xhy。";
        }
        taskTimingRecord.setContent(content);
    }


}
